package at.jku.ssw.fortress.ui;

import java.util.List;
import java.util.Stack;

import at.jku.ssw.fortress.ui.outline.Definition;

import com.sun.fortress.nodes.AbsDeclOrDecl;
import com.sun.fortress.nodes.AbsFnDecl;
import com.sun.fortress.nodes.AbsObjectDecl;
import com.sun.fortress.nodes.AbsTraitDecl;
import com.sun.fortress.nodes.AbsVarDecl;
import com.sun.fortress.nodes.Component;
import com.sun.fortress.nodes.FnDecl;
import com.sun.fortress.nodes.Node;
import com.sun.fortress.nodes.NodeAbstractVisitor;
import com.sun.fortress.nodes.ObjectDecl;
import com.sun.fortress.nodes.TraitDecl;
import com.sun.fortress.nodes.VarDecl;

public class AbstractModelExtractor extends NodeAbstractVisitor<Definition> {
	
	private Stack<Definition> stack = new Stack<Definition>();
	
	@Override
	public Definition forComponent(Component x) {
	    return forDecls(null,x,x.getDecls());
	}

    private Definition forDecls(Definition parent, Node x, List<? extends AbsDeclOrDecl> decls) {
        Definition d = new Definition(parent, x);
        stack.push(d);
        visitDecls(d, decls);
        stack.pop();
        return d;
    }
	
	public Definition parent() {
		if(stack.isEmpty()) {
			return null;
		}
		return stack.peek();
	}
	

	@Override
	public Definition forTraitDecl(TraitDecl x) {
	    return forDecls(parent(),x,x.getDecls());
	}
	
	@Override
	public Definition forAbsTraitDecl(AbsTraitDecl x) {
	    return forDecls(parent(),x,x.getDecls());
	}
	
	
	@Override
	public Definition forObjectDecl(ObjectDecl x) {
	    return forDecls(parent(),x,x.getDecls());
	}
	
	@Override
	public Definition forAbsObjectDecl(AbsObjectDecl x) {
	    return forDecls(parent(),x,x.getDecls());
	}
	
	@Override
	public Definition forVarDecl(VarDecl x) {
		Definition d = new Definition(parent(), x);
		return d;
	}
	
	@Override
	public Definition forFnDecl(FnDecl x) {
		Definition d = new Definition(parent(), x);
		return d;
	}
	
	@Override
	public Definition forAbsVarDecl(AbsVarDecl x) {
		Definition d = new Definition(parent(), x);
		return d;
	}
	
	@Override
	public Definition forAbsFnDecl(AbsFnDecl x) {
		Definition d = new Definition(parent(), x);
		return d;
	}
	
	private void visitDecls(Definition d, List<? extends AbsDeclOrDecl> defs) {
		for(AbsDeclOrDecl y : defs) {
			d.addDefiniton(visit(y));
		}
	}
	
	private Definition visit(AbsDeclOrDecl n) {
		return n.accept(this);
	}
	
}
